#pragma once
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include<functional>


#include "log.hpp" 
#include "Threadpool.hpp"
// #include "DangeTP.hpp"
#include "Task.hpp"

using namespace std;

namespace TCPSever
{

	static const int gbacklog = 5;
	enum
	{
		SOCK_ERR = 1,
		BIND_ERR,
		LISTEN_ERR,
	};

	class Sever
	{
	public:
		Sever(uint16_t port)
			: _port(port)
		{
		}

		void InitSever()
		{
			// TCP服务器的搭建，本质同UDP差不太多，在初始化阶段，应该先指明端口号以及协议
			listen_sock = socket(AF_INET, SOCK_STREAM, 0);
			if (listen_sock == -1)
			{
				logMessage(FATAL, "socket build failed!");
				exit(SOCK_ERR);
			}
			logMessage(NORMAL,"Socket success");

			// sock创建完毕后，接下来就是对应的绑定环节，因为目前的端口号和IP都只是在当前程序的栈上，要让内核知道，要调用bind
			// bind之前，依旧是填写对应的套接字结构

			struct sockaddr_in local;
			bzero(&local, sizeof(local));

			local.sin_family = AF_INET;
			local.sin_port = htons(_port);
			local.sin_addr.s_addr = htonl(INADDR_ANY);

			int n = bind(listen_sock, (sockaddr *)&local, sizeof(local));
			if (n == -1)
			{
				logMessage(FATAL, "bind failed!");
				exit(BIND_ERR);
			}
			logMessage(NORMAL,"bind success");

			// 由于是TCP服务器，我们不能像UDP那样简单粗暴的直接拿取 信息就完事了。 我们需要建立连接先。
			// 而建立链接的过程，同等与张三拉客，需要先进入监听状态。
			// 调用listen函数，使当前的socket进入监听状态，也就是拉客状态
			if(listen(listen_sock,gbacklog) < 0)
			{
				logMessage(ERROR, "enter listen failed!");
				exit(LISTEN_ERR);
			}
			logMessage(NORMAL,"now sever is listening...");

			// till now , the init operate is finished;
		}

		void start()
		{
			ThreadPool<Task>* tp = new ThreadPool<Task>;
			tp ->run();
			// 启动服务器
			// TCP的链接不仅需要先进入监听状态，还需要进行accept，也就是有客人愿意来
			// 客人来了叫店内的服务员来服务，张三继续出门拉客,客人来了，描述一下相貌和吹吹水，也就是获取一下其输出参数
			logMessage(NORMAL, "Thread init success");
			while(1)
			{
				struct sockaddr_in peer;
				socklen_t len  = sizeof(peer);

				int sock = accept(listen_sock,(struct sockaddr*)&peer,&len);
				// 如果拉客失败，那么需要终止进程吗？肯定不需要，因为可以马上寻找下一个目标。


				cout<<"调试打印1"<<endl;
                if (sock < 0)
                {
                    logMessage(ERROR, "accept error, next");
					// 重新拉客
                    continue;
                }
				// 拉客成功，接下来就是对目标客户提供服务
				// 版本一：简单的消息复读回显

				// ServiceIO(sock);
				//  走到这里，已经服务完毕，需要关闭对应的fd，不然可能造成FD泄露

				tp->push(Task(sock,ServiceIO));

				// close(sock);
			}
		}


		~Sever()
		{
		}

	private:
		uint16_t _port;
		int listen_sock;

	};

}